package com.wfh.mianshiji.tts;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.sound.sampled.AudioFormat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * 音频格式转换工具类
 * 主要用于将阿里云TTS返回的PCM格式音频转换为MP3格式
 *
 * @author fenghuanwang
 */
@Slf4j
@Component
public class AudioConverter {

    @Resource
    private Mp3Encoder mp3Encoder;

    /**
     * 将PCM音频数据转换为MP3格式
     * 使用高级MP3编码器，支持多种编码方案：
     * 1. 尝试使用系统FFmpeg进行真正的MP3编码
     * 2. 备选方案：高质量WAV格式
     * 3. 最终备选：MP3兼容的Base64编码数据
     *
     * @param pcmData PCM格式的音频数据
     * @param sampleRate 采样率
     * @param channels 声道数
     * @param sampleSizeInBits 样本大小
     * @return 转换后的MP3数据（包含data URL前缀）
     */
    public byte[] convertPcmToMp3(byte[] pcmData, int sampleRate, int channels, int sampleSizeInBits) {
        try {
            log.info("开始MP3编码：PCM({} bytes) -> MP3, 采样率: {}, 声道: {}, 位深: {}",
                    pcmData.length, sampleRate, channels, sampleSizeInBits);

            // 使用新的MP3编码器进行转换
            return mp3Encoder.convertPcmToMp3(pcmData, sampleRate, channels, sampleSizeInBits);

        } catch (Exception e) {
            log.error("PCM到MP3转换失败，使用备选方案", e);
            // 转换失败时返回Base64编码的PCM数据
            return encodePcmToBase64(pcmData);
        }
    }

    /**
     * 使用JLayer库将PCM转换为MP3
     * 注意：需要在pom.xml中添加依赖：
     * <dependency>
     *     <groupId>javazoom</groupId>
     *     <artifactId>jlayer</artifactId>
     *     <version>1.0.1</version>
     * </dependency>
     */
    private byte[] convertWithJLayer(byte[] pcmData, int sampleRate, int channels, int sampleSizeInBits) {
        // 注意：这里只是一个示例框架
        // JLayer主要用于MP3解码，编码需要使用其他库如LAME-java

        log.warn("JLayer MP3编码功能需要额外依赖，当前返回Base64编码的PCM数据");
        return encodePcmToBase64(pcmData);

        /*
        // 实际实现可能类似这样（需要正确的MP3编码库）：
        try {
            AudioFormat pcmFormat = new AudioFormat(
                AudioFormat.Encoding.PCM_SIGNED,
                sampleRate,
                sampleSizeInBits,
                channels,
                (sampleSizeInBits / 8) * channels,
                sampleRate,
                false
            );

            ByteArrayInputStream inputStream = new ByteArrayInputStream(pcmData);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // 使用MP3编码器进行转换
            // MP3Encoder encoder = new MP3Encoder();
            // encoder.encode(inputStream, outputStream, pcmFormat);

            return outputStream.toByteArray();
        } catch (Exception e) {
            log.error("MP3编码失败", e);
            return pcmData;
        }
        */
    }

    /**
     * 将PCM数据编码为Base64字符串的字节数组
     * 这样前端可以直接使用音频播放器播放
     */
    private byte[] encodePcmToBase64(byte[] pcmData) {
        String base64String = "data:audio/pcm;base64," + Base64.getEncoder().encodeToString(pcmData);
        return base64String.getBytes();
    }

    /**
     * 将PCM数据转换为WAV格式
     * WAV格式比PCM多了一个头部信息，更容易播放
     */
    public byte[] convertPcmToWav(byte[] pcmData, int sampleRate, int channels, int sampleSizeInBits) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // WAV文件头
            writeWavHeader(outputStream, pcmData.length, sampleRate, channels, sampleSizeInBits);

            // PCM数据
            outputStream.write(pcmData);

            return outputStream.toByteArray();
        } catch (IOException e) {
            log.error("PCM到WAV转换失败", e);
            return pcmData;
        }
    }

    /**
     * 写入WAV文件头
     */
    private void writeWavHeader(ByteArrayOutputStream outputStream, int dataLength,
                               int sampleRate, int channels, int sampleSizeInBits) throws IOException {
        int byteRate = sampleRate * channels * (sampleSizeInBits / 8);
        int blockAlign = channels * (sampleSizeInBits / 8);

        // RIFF头部
        outputStream.write("RIFF".getBytes());
        outputStream.write(intToByteArray(36 + dataLength), 0, 4); // 文件大小-8
        outputStream.write("WAVE".getBytes());

        // fmt子块
        outputStream.write("fmt ".getBytes());
        outputStream.write(intToByteArray(16), 0, 4); // fmt子块大小
        outputStream.write(shortToByteArray((short) 1), 0, 2); // 音频格式（PCM = 1）
        outputStream.write(shortToByteArray((short) channels), 0, 2); // 声道数
        outputStream.write(intToByteArray(sampleRate), 0, 4); // 采样率
        outputStream.write(intToByteArray(byteRate), 0, 4); // 字节率
        outputStream.write(shortToByteArray((short) blockAlign), 0, 2); // 块对齐
        outputStream.write(shortToByteArray((short) sampleSizeInBits), 0, 2); // 位深

        // data子块
        outputStream.write("data".getBytes());
        outputStream.write(intToByteArray(dataLength), 0, 4); // 数据大小
    }

    /**
     * 将整数转换为小端序字节数组
     */
    private byte[] intToByteArray(int value) {
        return new byte[] {
            (byte) (value & 0xFF),
            (byte) ((value >> 8) & 0xFF),
            (byte) ((value >> 16) & 0xFF),
            (byte) ((value >> 24) & 0xFF)
        };
    }

    /**
     * 将短整数转换为小端序字节数组
     */
    private byte[] shortToByteArray(short value) {
        return new byte[] {
            (byte) (value & 0xFF),
            (byte) ((value >> 8) & 0xFF)
        };
    }

    /**
     * 检测音频格式并转换为合适的格式
     */
    public AudioFormatInfo detectAudioFormat(byte[] audioData) {
        // 阿里云TTS通常返回PCM格式，参数如下：
        return new AudioFormatInfo(
            24000,  // 采样率：24kHz
            1,      // 声道数：单声道
            16,     // 位深：16位
            "pcm"   // 格式：PCM
        );
    }

    /**
     * 音频格式信息类
     */
    public static class AudioFormatInfo {
        private final int sampleRate;
        private final int channels;
        private final int sampleSizeInBits;
        private final String format;

        public AudioFormatInfo(int sampleRate, int channels, int sampleSizeInBits, String format) {
            this.sampleRate = sampleRate;
            this.channels = channels;
            this.sampleSizeInBits = sampleSizeInBits;
            this.format = format;
        }

        // Getters
        public int getSampleRate() { return sampleRate; }
        public int getChannels() { return channels; }
        public int getSampleSizeInBits() { return sampleSizeInBits; }
        public String getFormat() { return format; }
    }
}